package com.to8to.kitt.esb;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.thrift.TBaseProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;

import com.to8to.kitt.SyncBizChannelHandler;
import com.to8to.kitt.ThriftBizServerChannelInitializer;
import com.to8to.kitt.ThriftClassFactory;
import com.to8to.kitt.utils.LogUtils;
import com.to8to.kitt.utils.NettyUtils;

public class DefaultServerDeamon extends AbstractServerDeamon{

	public String ThreadPoolConfigPath = "/config/crm/common/threadpool.conf";
	
	public String serverFile = "server.properties";
	
	@Override
	public void onPrivateConfigChange(Map<String, NodeChangeEvent> config) {
		
		String[] files = {serverFile};
		
		for(String file: files)
		{
			NodeChangeEvent event = config.get(file);
			
			if (event == null) {
				logger.warn("服务配置找不到: " + file);
				continue;
			}
			
			if(!event.isChange())
			{
				System.out.println("服务地址配置不变:server.properties, 忽略之!");
				continue;
			}
			
			byte[] data = event.ndata;
		
			if(file.equals(serverFile))
			{
				try {
			
					System.out.println("----------加载服务地址配置:\n" + new String(data));
					
					PropertiesConfiguration pc = new PropertiesConfiguration();
					
					pc.load(new ByteArrayInputStream(data));
					
					String bind_host = pc.getString("bind_host");
					
					String report_host = pc.getString("report_host");
					
					int bind_port = pc.getInt("bind_port");
					
					int report_port = pc.getInt("report_port");
					
					super.bindAndReport(bind_host, bind_port, report_host, report_port);
					
				} catch (ConfigurationException e) {
					logger.error(LogUtils.logStackTrace(e));
				}
			}
		}
	}

	@Override
	public void onCommonConfigChange(NodeChangeEvent e) {
		if(e.isChange())
		{
			if(e.path.equals(ThreadPoolConfigPath))
			{
				try {
					
					PropertiesConfiguration pc = new PropertiesConfiguration();
					
					pc.load(new ByteArrayInputStream(e.ndata));
					
					NettyUtils.EXIT_IF_OUT_OF_MEM = pc.getBoolean("exit_if_out_of_memory", true);
					
					System.out.println("reload " + ThreadPoolConfigPath + ", exit_if_out_of_memory=" + NettyUtils.EXIT_IF_OUT_OF_MEM);
					
				} catch (ConfigurationException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
	}

	
	private void doStart(Object iface, Class<?> serviceclass)
	{
		Map<Class<?>, Object> serviceMap = new HashMap<Class<?>, Object>();
		
		serviceMap.put(serviceclass, iface);
		
		doStart(serviceMap, serviceclass);
	}
	
	
	
	public void startWithoutZK(Object iface, Class<?> serviceclass, String host, int port)
	{
		setSyncConfigFromZK(false);

		setReportAddressToZK(false);
		
		setBindHost(host);
		
		setBindPort(port);
		
		doStart(iface, serviceclass);
	}
	
	
	public void start(Map<Class<?>, Object> serviceMap, Class<?> reportServiceClass, String instance)
	{
		setSyncConfigFromZK(true);

		setReportAddressToZK(true);

		setServiceInstance(reportServiceClass.getName(), instance);
		
		doStart(serviceMap, reportServiceClass);
	}
	
	public void start(Object iface, Class<?> serviceclass, String instance)
	{
		setSyncConfigFromZK(true);

		setReportAddressToZK(true);

		setServiceInstance(serviceclass.getName(), instance);
		
		doStart(iface, serviceclass);
	}
	
	private void doStart(Map<Class<?>, Object> serviceMap, Class<?> reportServiceClass)
	{
		int size = serviceMap.size();
		
		TBaseProcessor<?>[] processors = new TBaseProcessor[size];
		
		Class<?>[] serviceclasses = new Class<?>[size];
		
		int i = 0 ;
		
		try {
			
			for(Class<?> serviceclass : serviceMap.keySet())
			{
				Object iface = serviceMap.get(serviceclass);
				
				Class<?>[] classes = serviceclass.getDeclaredClasses();
				
				Class<?> ifaceClass = null;
				
				Class<?> processorClass = null;
				
				for(Class<?> cls : classes)
				{
					if(cls.getSimpleName().equals("Iface"))
						ifaceClass = cls;
					if(cls.getSimpleName().equals("Processor"))
						processorClass = cls;
					
				}
				
				processors[i] = (TBaseProcessor<?>)processorClass.getConstructor(ifaceClass).newInstance(iface);
				
				serviceclasses[i] = serviceclass;
				
				++ i;
			}
			
			SyncBizChannelHandler bizhandler = new SyncBizChannelHandler(processors);
			
			{
				byte[] data = ZK.ZK_CLIENT.getData().forPath(ThreadPoolConfigPath);
				PropertiesConfiguration pc = new PropertiesConfiguration();
				pc.load(new ByteArrayInputStream(data));
				int max_io_thread = pc.getInt("max_io_thread");
				int max_biz_thread = pc.getInt("max_biz_thread");
				int max_task = pc.getInt("max_task");
				
				boolean exit_if_out_of_memory = pc.getBoolean("exit_if_out_of_memory", true);
				
				NettyUtils.EXIT_IF_OUT_OF_MEM = exit_if_out_of_memory;
				
				System.out.println("-----------------threadpool.conf---------------------------------");
				System.out.println("max_io_thread:" + max_io_thread);
				System.out.println("max_biz_thread:" + max_biz_thread);
				System.out.println("max_task:" + max_task);
				System.out.println("exit_if_out_of_memory:" + exit_if_out_of_memory);
				System.out.println("------------------------------------------------------------------");
				
				bizhandler.setMaxBizThreads(max_biz_thread);
				bizhandler.setMaxTasks(max_task);
//				super.setMaxIOThreads(max_io_thread);
				bizhandler.initThreadPool();
			}
			

			ThriftClassFactory.init(new TBinaryProtocol.Factory(), null, serviceclasses);
			
			ThriftBizServerChannelInitializer channelInitilizer = new ThriftBizServerChannelInitializer(bizhandler);

			setChannelInitilizer(channelInitilizer);

			init();
			
		} catch (Exception e) {
			logger.error(LogUtils.logStackTrace(e));
		}
	}
}
